package com.example.parent.bookmanage_security.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

import javax.sql.DataSource;

/**
 * Spring Security 核心配置类
 * 配置认证授权规则、登录逻辑、密码加密方式等安全相关功能
 */
@Configuration // 标识为Spring配置类，会被Spring容器扫描并加载
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
// 启用全局方法级安全控制：
// - prePostEnabled = true：支持@PreAuthorize、@PostAuthorize等注解
// - securedEnabled = true：支持@Secured注解进行方法权限控制
public class WebSecurityConfig {

    /**
     * 注入数据源
     * 用于从数据库加载用户信息和权限数据（配合JdbcUserDetailsManager使用）
     */
    @Autowired
    private DataSource dataSource;

    /**
     * 配置密码编码器
     * 使用BCrypt加密算法对密码进行加密存储，增强安全性
     *
     * @return BCryptPasswordEncoder实例
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 用户详情服务配置（当前注释掉，可根据需求启用）
     * 提供两种用户信息加载方式：内存存储和数据库存储
     */
//    @Bean
//    public UserDetailsService userDetailsService() {
//        // 方式一：使用内存存储用户信息（适合测试环境）
//        InMemoryUserDetailsManager users = new InMemoryUserDetailsManager();
//        users.createUser(
//                User.withUsername("zhangsan")  // 用户名
//                        .password("{noop}1234") // 密码，{noop}表示不加密（仅测试用）
//                        .roles("ADMIN")        // 角色
//                        .build()
//        );
//
//        // 方式二：使用数据库存储用户信息（适合生产环境）
//        // 定义查询用户信息的SQL
//        String userSQL = "select username, password, valid from user where username = ?";
//        // 定义查询用户权限的SQL
//        String authoritySQL = "select u.username, p.authority from user u, priv p, user_priv up where up.user_id=u.id and up.priv_id=p.id and u.username = ?";
//        JdbcUserDetailsManager users = new  JdbcUserDetailsManager();
//        users.setDataSource(dataSource); // 设置数据源
//        users.setUsersByUsernameQuery(userSQL); // 设置查询用户信息的SQL
//        users.setAuthoritiesByUsernameQuery(authoritySQL); // 设置查询用户权限的SQL
//        return users;
//    }

    /**
     * 配置安全过滤链
     * 定义URL访问规则、登录逻辑、CSRF防护等安全策略
     *
     * @param http HttpSecurity对象，用于配置HTTP安全相关设置
     * @return SecurityFilterChain实例，包含所有安全配置
     * @throws Exception 配置过程中可能抛出的异常
     */
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                // 配置请求授权规则
                .authorizeHttpRequests(auth -> auth
                        // 允许所有人访问登录页面和静态资源（CSS、图片等）
                        .requestMatchers("/loginView", "/css/**", "/img/**").permitAll()
                        // 访问/book/admin/**路径需要ADMIN角色
                        .requestMatchers("/book/admin/**").hasRole("ADMIN")
                        // 其他所有请求都需要认证（登录后才能访问）
                        .anyRequest().authenticated()
                )
                // 配置表单登录
                .formLogin(form -> form
                        .loginPage("/loginView") // 指定自定义登录页面路径
                        .loginProcessingUrl("/doLogin") // 指定登录请求处理路径（Spring Security内部处理）
                        .permitAll() // 允许所有用户访问登录相关页面和接口
                )
                // 关闭CSRF防护（跨站请求伪造）
                // 注意：生产环境中不建议关闭，需根据前端情况正确配置CSRF令牌
                .csrf(AbstractHttpConfigurer::disable)
                // 配置响应头，允许同源的iframe嵌入（如H2数据库控制台需要此配置）
                .headers(headers -> headers
                        .frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)
                )
                // 配置会话管理策略
                .sessionManagement(
                        session -> session
                                // 设置会话创建策略为NEVER：Spring Security不创建会话，若已有会话则使用
                                .sessionCreationPolicy(SessionCreationPolicy.NEVER)
                );
        // 构建并返回安全过滤链
        return http.build();
    }
}